﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace craigsPack
{
    /// <summary>
    /// Provides a custom constructor to build and modify variables in a URI
    /// </summary>
    public class QueryStringBuilder
    {
        private int counter;
        protected string query;
        

        protected QueryStringBuilder()
        {
            Variables = new string[10];
        }
        /// <summary>
        /// Adds a query variable to the current query string
        /// </summary>
        /// <param name="variable">name of variable in query string</param>
        /// <param name="value">value of variable in query string</param>
        protected void SetVariable(string variable, string value)
        {
            if (Variables.Any(o => o != null && GetVarName(o) == variable))
                throw new ArgumentException("variable already set");
            if (counter + 1 > Variables.Length)
            {
                //Copys variables and adds 5 new indexs to new array when space is needed
                string[] tempVars = new string[Variables.Length + 5];
                Variables.CopyTo(tempVars, 0);
                Variables = tempVars;
                tempVars = null;
            }

            Variables[counter] =  variable + '=' + value;
            counter++;
        }
        /// <summary>
        /// Modify a exisitng variables value in the query string
        /// </summary>
        /// <param name="variable">name of variable</param>
        /// <param name="newValue">new value of variable</param>
        protected void ModifyVariable(string variable, string newValue)
        {
            if (!Variables.Any(o => o != null && GetVarName(o) == variable))
                throw new ArgumentException("no such variable found");
            int opIndex = Variables[GetIndexOf(variable)].IndexOf('=');
            string newVar = Variables[GetIndexOf(variable)];

            if(opIndex + 1 != Variables[GetIndexOf(variable)].Length)
                newVar = newVar.Remove(newVar.IndexOf('=') + 1);

           Variables[GetIndexOf(variable)] = newVar.Insert(newVar.IndexOf('=') + 1, newValue);
            
        }
        /// <summary>
        /// Returns the variable name from the Variables property
        /// </summary>
        /// <param name="variable">variable name</param>
        /// <returns></returns>
        protected string GetVarName(string variable)
        {
            return variable.Substring(0, variable.IndexOf('='));
        }
        /// <summary>
        /// Returns whether a specified variable is set
        /// </summary>
        /// <param name="variable"></param>
        /// <returns></returns>
        protected bool HasVariable(string variable)
        {
            foreach (var item in Variables)
            {
                if (item != null && GetVarName(item) == variable)
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Returns the index of the variable from the Variables property
        /// </summary>
        /// <param name="variable"></param>
        /// <returns></returns>
        protected int GetIndexOf(string variable)
        {
            for (int i = 0; i < Variables.Length; i++)
            {
                if (Variables[i] != null && GetVarName(Variables[i]) == variable)
                    return i;
            }
            return -1;
        }
       /// <summary>
       /// Gets the complete query string
       /// </summary>
        public string Query
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                foreach (var item in Variables)
                {
                    if(item != null)
                       sb.Append("&" + item);
                }

                return sb.ToString();
            }
        }
        /// <summary>
        /// Gets the variables in the query string
        /// </summary>
        private string[] Variables { get; set; }
        /// <summary>
        /// Gets if any variables have been set
        /// </summary>
        public bool HasVariables
        {
            get { return Variables.All(o => o != null); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="variable">variable name</param>
        /// <returns></returns>
        public virtual object this[string variable]
        {
            get 
            {
                if (!HasVariables)
                    throw new KeyNotFoundException("No variable " + '\'' + variable + '\'' + " found");

                return Variables[GetIndexOf(variable)]; 
            }
            set 
            {
                if (GetIndexOf(variable) == -1)
                    SetVariable(variable, value.ToString());
                else
                    ModifyVariable(variable, value.ToString());
            }
        }
    }
}
